﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.IO;
using System.Text;
using System.Windows.Forms;

using System.Reflection;
using Microsoft.HomeServer.Controls;
using Microsoft.HomeServer.Controls.QSM;
using qsmif;

namespace Microsoft.HomeServer.HomeServerConsoleTab.DuplicationInfo
{
    public partial class ShowDuplicationInfoPanel : UserControl
    {
        public const string SHARES_LOCATION = @"D:\";
        public readonly int STICKY_COLUMNS;

        public ShowDuplicationInfoPanel()
        {
            InitializeComponent();

            this.STICKY_COLUMNS = this.fileListView.Columns.Count;
            this.versionToolStripLabel.Text = string.Format("Version: {0}", Assembly.GetAssembly(this.GetType()).GetName().Version);
            SetupVolumes();

            Icon icon = ShellIcon.GetIcon(Environment.GetEnvironmentVariable("SystemRoot"));
            if (icon != null)
            {
                using (icon)
                {
                    this.folderImageList.Images.Add(icon);
                }
            }
            this.folderTreeView.Nodes[0].Expand();
        }

        private void SetupVolumes()
        {
            try
            {
                fileListView.BeginUpdate();
                IList<int> widths = new List<int>();

                while (fileListView.Columns.Count > STICKY_COLUMNS)
                {
                    widths.Add(fileListView.Columns[STICKY_COLUMNS].Width);
                    fileListView.Columns.RemoveAt(STICKY_COLUMNS);
                }

                foreach (Disk disk in QSMMgr.GetDisks())
                {
                    if (disk.Role != DiskRole.SystemDisk && disk.Role != DiskRole.StorageDisk)
                    {
                        continue;
                    }

                    foreach (Object obj in disk.QsmDisk.QueryObjects(QSM_OBJECT_TYPE.QSM_OT_VOLUME))
                    {
                        IQSMVolume volume = (IQSMVolume)obj;
                        if (volume.Status != QSM_OBJECT_STATUS.QSM_OS_HEALTHY)
                        {
                            continue;
                        }

                        if (volume.Path != @"C:\")
                        {
                            ColumnHeader header = new ColumnHeader();
                            header.Text = disk.Name;
                            switch (disk.Role)
                            {
                                case DiskRole.SystemDisk:
                                    header.Text += "(SYS)";
                                    break;
                            }
                            header.Tag = volume.ObjectName;
                            header.TextAlign = HorizontalAlignment.Center;
                            if (fileListView.Columns.Count - STICKY_COLUMNS < widths.Count)
                            {
                                header.Width = widths[fileListView.Columns.Count - STICKY_COLUMNS];
                            }

                            fileListView.Columns.Add(header);
                        }
                    }
                }
            }
            finally
            {
                fileListView.EndUpdate();
            }
        }

        private void ShowFiles(string path)
        {
            SetupVolumes();
            try
            {
                fileListView.BeginUpdate();
                fileListView.Items.Clear();

                fileImageList.Images.Clear();

                string[] files;
                try
                {
                    files = Directory.GetFiles(path);
                }
                catch (DirectoryNotFoundException)
                {
                    MessageBox.Show("Selected directory not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                foreach (string file in files)
                {
                    ListViewItem item = new ListViewItem();
                    item.Text = Path.GetFileName(file);

                    Icon icon = ShellIcon.GetIcon(file);
                    if (icon != null)
                    {
                        using (icon)
                        {
                            fileImageList.Images.Add(icon);
                            item.ImageIndex = fileImageList.Images.Count - 1;
                        }
                    }

                    try
                    {
                        FileInfo info = new FileInfo(file);
                        item.SubItems.Add(string.Format("{0:n0} KB", (info.Length + 1023) / 1024));
                    }
                    catch (IOException)
                    {
                        item.SubItems.Add("Unknown");
                    }
                    catch (SystemException)
                    {
                        item.SubItems.Add("Unknown");
                    }

                    try
                    {
                        ReparsePoint.REPARSE_GUID_DATA_BUFFER buf = ReparsePoint.GetReparsePointData(file);
                        DriveExtenderReparsePointData data = new DriveExtenderReparsePointData(buf);

                        foreach (ColumnHeader header in fileListView.Columns)
                        {
                            if (header.Index < STICKY_COLUMNS)
                            {
                                continue;
                            }

                            if (data.Guids.Contains((Guid)header.Tag))
                            {
                                item.SubItems.Add("\u2713");
                            }
                            else
                            {
                                item.SubItems.Add(string.Empty);
                            }
                        }
                    }
                    catch (IOException ex)
                    {
                        item.SubItems.Add(ex.Message);
                    }
                    catch (ArgumentException ex)
                    {
                        item.SubItems.Add(ex.Message);
                    }

                    fileListView.Items.Add(item);
                }
            }
            finally
            {
                fileListView.EndUpdate();
            }
        }

        private void folderTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            e.Node.Nodes.Clear();
            try
            {
                foreach (string dir in Directory.GetDirectories(SHARES_LOCATION + e.Node.FullPath))
                {
                    TreeNode node = new TreeNode();
                    node.Nodes.Add("dummy");
                    node.Text = node.Name = Path.GetFileName(dir);
                    e.Node.Nodes.Add(node);
                }
            }
            catch (IOException) { }
            catch (SystemException) { }
        }

        private void refreshFolderTreeView()
        {
            foreach(TreeNode node in folderTreeView.Nodes){
                refreshFolderTreeNode(node);
            }
        }

        private void refreshFolderTreeNode(TreeNode node)
        {
            if (node.IsExpanded)
            {
                if (node.Nodes.Count == 0)
                {
                    node.Collapse();
                    node.Nodes.Add("dummy");
                }
                else
                {
                    IList<string> dirs = new List<string>(
                        Directory.GetDirectories(SHARES_LOCATION + node.FullPath)
                        );

                    foreach (TreeNode child in node.Nodes)
                    {
                        if (dirs.Contains(SHARES_LOCATION + child.FullPath) == false)
                        {
                            child.Remove();
                        }
                    }

                    foreach (string dir in dirs)
                    {
                        if (node.Nodes[Path.GetFileName(dir)] == null)
                        {
                            TreeNode child = new TreeNode();
                            child.Text = child.Name = Path.GetFileName(dir);
                            node.Nodes.Add(child);
                        }
                    }

                    foreach (TreeNode child in node.Nodes)
                    {
                        refreshFolderTreeNode(child);
                    }
                }
            }
            else
            {
                node.Nodes.Clear();
                node.Nodes.Add("dummy");
            }
        }

        private void refreshFileListView()
        {
            TreeNode node = folderTreeView.SelectedNode;
            if (node != null)
            {
                string path = SHARES_LOCATION + node.FullPath;
                ShowFiles(path);
            }
        }

        private void folderTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if(e.Action == TreeViewAction.ByMouse && !e.Node.IsExpanded)
            {
                e.Node.Expand();
            }
            refreshFileListView();
        }

        private void refreshToolStripButton_Click(object sender, EventArgs e)
        {
            refreshFolderTreeView();
            refreshFileListView();
        }

        private void ShowDuplicationInfoPanel_ParentChanged(object sender, EventArgs e)
        {
            if (this.Parent != null)
            {
                refreshFolderTreeView();
                refreshFileListView();
            }
        }

        private void exploreToolStripButton_Click(object sender, EventArgs e)
        {
            TreeNode node = folderTreeView.SelectedNode;
            TreeNode root = folderTreeView.Nodes[0];
            if (node != null)
            {
                string prefix = @"\\" + Environment.MachineName;
                string path = prefix + node.FullPath.Substring(root.Text.Length);

                ClientCommunicator.ShowBrowse(path, !CommonSettings.LaunchBare);
            }
        }
    }
}
